package cn.always.xiajia.framework.rpc.core.fegin;

import java.util.List;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;

import com.alibaba.cloud.nacos.balancer.NacosBalancer;

import cn.always.xiajia.framework.common.util.ExtCollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@RequiredArgsConstructor
@Slf4j
public class RfqLoadBalancerClient implements ReactorServiceInstanceLoadBalancer {

	/**
	 * 用于获取 serviceId 对应的服务实例的列表
	 */
	private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

	/**
	 * 需要获取的服务实例名
	 *
	 * 暂时用于打印 logger 日志
	 */
	private final String serviceId;

	/**
	 * 被代理的 ReactiveLoadBalancer 对象
	 */
	private final ReactiveLoadBalancer<ServiceInstance> reactiveLoadBalancer;

	@Override
	public Mono<Response<ServiceInstance>> choose(Request request) {
		ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
		return supplier.get(request).next().map(list -> getInstanceResponse(list, null));
	}

	private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, String tag) {
		// 如果服务实例为空，则直接返回
		if (ExtCollUtil.isEmpty(instances)) {
			log.warn("[getInstanceResponse][serviceId({}) 服务实例列表为空]", serviceId);
			return new EmptyResponse();
		}

		// 随机 + 权重获取实例列表 目前直接使用 Nacos 提供的方法，如果替换注册中心，需要重新失败该方法
		return new DefaultResponse(NacosBalancer.getHostByRandomWeight3(instances));
	}

}
